%{
/*
 * ctoolparser.y:
 * Clunix, cezanne@clunix.com, 2006.7
 *
 * Copyright (c) 2001-2006 by Clunix Inc. All Rights Reserved.
 */

#include "config.h"

#include <stdio.h>

#include "ebctool.h"

#define YYMALLOC	ecm_malloc
#define YYFREE		ecm_free

#ifdef ECM_DEBUG
#define YYDEBUG	1
#else
#define YYDEBUG 0
#endif

#define YYSIZE_T	ecm_size_t

#define	MAX_STR_CONST	1024

extern int ctlineno;

int ctlex(void);
extern void cterror(char *);

%}

%union {
	ecm_int32	i_value;
	char	*s_value;
	sr_t	*sr;
       }

%start program

%token <i_value> ENDOFCMD ENDOFBUF
%token <i_value> Quit Help Error
%token <i_value> Connect PeerCon
%token <i_value> Call Call1 BCall TCall
%token <i_value> Send Recv BSend BRecv
%token <i_value> PeerBSend PeerBRecv
%token <i_value> EchoServer Route MonCb
%token <s_value> ErrorCmd Literal String
%type <i_value> program commands command quit_command
%type <i_value> err_command help_command
%type <i_value> connect_command peercon_command
%type <i_value> call_command call1_command bcall_command tcall_command
%type <i_value> send_command recv_command bsend_command brecv_command
%type <i_value> peerbsend_command peerbrecv_command
%type <i_value> moncb_command route_command
%type <i_value> echo_server_command
%type <s_value> literal help_context
%type <i_value> uinteger bulk_size optional_bulk_count
#DEBUG START
%token <i_value> MTrace Monitor CallInfo
%token <i_value> PCH PCH_Info PCH_List PKTB

%type <i_value> mtrace_command monitor_command
%type <i_value> pchinfo_command pktb_command callinfo_command
#DEBUG END
%%
program		: commands ENDOFBUF
		{
			printf("\n");
			YYACCEPT;
		}
		| commands quit_command
		{
			YYACCEPT;
		}
		;

commands	:
		{
			$$ = 0;
		}
		| commands command
		{
		}
		;

quit_command	: Quit ENDOFCMD;

command		: err_command
		| help_command
		| connect_command
		| peercon_command
		| call_command
		| call1_command
		| bcall_command
		| tcall_command
		| send_command
		| recv_command
		| bsend_command
		| brecv_command
		| peerbsend_command
		| peerbrecv_command
		| echo_server_command
		| moncb_command
		| route_command
#DEBUG START
		| mtrace_command
		| monitor_command
		| pchinfo_command
		| pktb_command
		| callinfo_command
#DEBUG END
		;

err_command	: error ENDOFCMD
		{
			/* TODO: */
			fprintf(stderr, "Invalid Command\n");
		}
		| ErrorCmd
		{
			fprintf(stderr, "Invalid Command\n");
		}
		;

help_command	: Help help_context ENDOFCMD
		{
			cmd_help($2);
		}
		;

connect_command	: Connect Literal ENDOFCMD
		{
			cmd_connect(NULL, 0, $2);
			ecm_free($2);
		}
		| Connect Literal Literal ENDOFCMD
		{
			cmd_connect($3, 0, $2);
			ecm_free($2);
			ecm_free($3);
		}
		| Connect Literal Literal Literal ENDOFCMD
		{
			ecm_uint16	port;

			if (ecm_sscanf($4, "%hu", &port) != 1) {
				fprintf(stderr, "%s: invalid port\n", $4);
				ecm_free($2);
				ecm_free($3);
				ecm_free($4);
			}
			else {
				cmd_connect($3, port, $2);
				ecm_free($2);
				ecm_free($3);
			}
		}
		| Connect error ENDOFCMD
		{
			fprintf(stderr, "connect command error!\nUsage: connect <mdname> [<serverip> [<port>]]\n");
		}
		;

peercon_command	: PeerCon Literal ENDOFCMD
		{
			cmd_peercon($2, 5000);
		}
		| PeerCon Literal Literal ENDOFCMD
		{
			ecm_uint32	timeout;

			if (ecm_sscanf($3, "%u", &timeout) != 1) {
				fprintf(stderr, "%s: invalid timeout\n", $3);
				ecm_free($2);
			}
			else {
				cmd_peercon($2, timeout);
			}
		}
		| PeerCon error ENDOFCMD
		{
			fprintf(stderr, "peercon command error!\nUsage: connect <peer address> [<timeout>]\n"); 
		}
		;

call_command	: Call Literal literal ENDOFCMD
		{
			cmd_call($2, 0, $3);
		}
		| Call error ENDOFCMD
		{
			fprintf(stderr, "Usage: call <target> <asr>\n");
			fprintf(stderr, "  eg) call pa/./ebcd/echo <str>hello;\n");
		}
		;

call1_command	: Call1 Literal literal ENDOFCMD
		{
			cmd_call_oneway($2, $3);
		}
		| Call1 error ENDOFCMD
		{
			fprintf(stderr, "Usage: call1 <target> <asr>\n");
			fprintf(stderr, "  eg) call pa/./ebcd/echo <str>hello;\n");
		}
		;

bulk_size	: uinteger;

optional_bulk_count:
		{
			$$ = 1;
		}
		| uinteger;
		;

bcall_command	: BCall Literal bulk_size optional_bulk_count ENDOFCMD
		{
			cmd_bcall($2, $3, $4);
		}
		| BCall error ENDOFCMD
		{
			fprintf(stderr, "Usage: bcall <target> <size in bytes> [<count>]\n");
		}
		;

tcall_command	: TCall Literal uinteger literal ENDOFCMD
		{
			cmd_call($2, $3, $4);
		}
		| TCall error ENDOFCMD
		{
			fprintf(stderr, "Usage: tcall <target> <timeout in msec> <asr>\n");
		}
		;

send_command	: Send Literal literal ENDOFCMD
		{
			cmd_send($2, $3);
		}
		| Send error ENDOFCMD
		{
			fprintf(stderr, "Usage: send <target> <asr>\n");
			fprintf(stderr, "  eg) send pa/./abc/test <str>hello;\n");
		}
		;

recv_command	: Recv literal ENDOFCMD
		{
			cmd_recv($2);
		}
		| Recv error ENDOFCMD
		{
			fprintf(stderr, "Usage: recv <pattern>\n");
		}
		;

bsend_command	: BSend Literal bulk_size optional_bulk_count ENDOFCMD
		{
			cmd_bsend($2, $3, $4);
		}
		| BSend error ENDOFCMD
		{
			fprintf(stderr, "Usage: bsend <target> <size in bytes> [ <count>]\n");
		}
		;

brecv_command	: BRecv literal optional_bulk_count ENDOFCMD
		{
			cmd_brecv($2, $3);
		}
		| BRecv error ENDOFCMD
		{
			fprintf(stderr, "Usage: brecv <pattern> [<count>]\n");
		}
		;

peerbsend_command: PeerBSend bulk_size optional_bulk_count ENDOFCMD
		{
			cmd_peerbsend($2, $3);
		}
		| PeerBSend error ENDOFCMD
		{
			fprintf(stderr, "Usage: peerbsend <size in bytes> [ <count>]\n");
		}
		;

peerbrecv_command: PeerBRecv optional_bulk_count ENDOFCMD
		{
			cmd_peerbrecv($2);
		}
		| PeerBRecv error ENDOFCMD
		{
			fprintf(stderr, "Usage: peerbrecv [<count>]\n");
		}
		;

literal		: String | Literal;

help_context	:
		{
			$$ = NULL;
		}
		|  literal
		{
			$$ = $1;
		};

echo_server_command : EchoServer ENDOFCMD
		{
			cmd_echo_server();
		}
		;

moncb_command	: MonCb Literal literal ENDOFCMD
		{
			if (ecm_strcmp($2, "add") == 0)
				cmd_moncb_add($3);
			else if (ecm_strcmp($2, "del") == 0)
				cmd_moncb_del($3);
			else
				fprintf(stderr, "Usage: moncb {add|del} <target>\n");
			ecm_free($2);
		}

route_command	: Route ENDOFCMD
		{
			cmd_route_print();
		}
		| Route Literal literal ENDOFCMD
		{
			if (ecm_strcmp($2, "add") == 0)
				cmd_route_add($3);
			else if (ecm_strcmp($2, "del") == 0)
				cmd_route_del($3);
			else
				fprintf(stderr, "Usage: route {add|del} <addrspec>\n");
			ecm_free($2);
			ecm_free($3);
		}
		| Route error ENDOFCMD
		{
			fprintf(stderr, "Usage: route {add|del} <addrspec>\n");
		}
		;

uinteger	: Literal
		{
			ecm_uint32	value;

			if (ecm_sscanf($1, "%u", &value) != 1) {
				fprintf(stderr, "%s: invalid integer\n", $1);
				ecm_free($1);
				YYERROR;
			}
			$$ = value;
			ecm_free($1);
		}
		;

#DEBUG START
pchinfo_command	: PCH ENDOFCMD
		{
			cmd_pch_info(NULL);
		}
		| PCH PCH_Info literal ENDOFCMD
		{
			cmd_pch_info($3);
			ecm_free($3);
		}
		| PCH PCH_List ENDOFCMD
		{
			cmd_pch_list();
		}
		| PCH Error
		{
			fprintf(stderr, "Usage: pch [list|info]\n");
		}
		;

pktb_command	: PKTB ENDOFCMD
		{
			cmd_pktb();
		}
		;

callinfo_command	: CallInfo ENDOFCMD
		{
			cmd_call_info();
		}
		;

monitor_command	: Monitor ENDOFCMD
		{
			cmd_monitor_info();
		}
		;

mtrace_command	: MTrace ENDOFCMD
		{
			cmd_mtrace_info();
		}
		| MTrace Literal ENDOFCMD
		{
			if (ecm_strcmp($2, "off") == 0)
				cmd_mtrace_off();
			else if (ecm_strcmp($2, "report") == 0)
				cmd_mtrace_report();
			else if (ecm_strcmp($2, "clear") == 0)
				cmd_mtrace_clear();
			else
				fprintf(stderr, "Usage: mtrace [on <level>|off|report|clear]\n");
			ecm_free($2);
		}
		| MTrace Literal Literal ENDOFCMD
		{
			ecm_uint32	level;

			if (ecm_sscanf($3, "%u", &level) != 1)
				level = 4;

			if (ecm_strcmp($2, "on") == 0)
				cmd_mtrace_on(level, ECM_FALSE);
			else if (ecm_strcmp($2, "selfon") == 0)
				cmd_mtrace_on(level, ECM_TRUE);
			else
				fprintf(stderr, "Usage: mtrace [on <level>|off|report|clear]\n");
			ecm_free($2);
			ecm_free($3);
		}
		;
#DEBUG END
%%
